Skip to content

Commit

Permalink
tests: llext: Add RISC-V CB-Type edge case test
Browse files Browse the repository at this point in the history
All immediates in RISC-V are encoded as two's complement. This commit
adds a test for relocating jumps that utilize the full range of the
immediate, in both positive and negative direction.
To this end, the test uses the compressed b-type (CB) instruction to
branch to its maximum negative (-256) and maximum positive (+254)
targets.
In case of test failure, expect relocating the corresponding llext to
fail.

Signed-off-by: Eric Ackermann <eric.ackermann@cispa.de>
  • Loading branch information
WorldofJARcraft committed Dec 21, 2024
1 parent 7e1f7fa commit 9381ec2
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 1 deletion.
10 changes: 10 additions & 0 deletions tests/subsys/llext/simple/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,13 @@ if (CONFIG_LLEXT_TYPE_ELF_RELOCATABLE AND NOT CONFIG_ARM AND NOT CONFIG_RISCV)
$<TARGET_OBJECTS:${pre_located_target}> -o ${pre_located_file}
)
endif()

if(NOT CONFIG_LLEXT_TYPE_ELF_OBJECT AND CONFIG_RISCV AND CONFIG_RISCV_ISA_EXT_C)
add_llext_target(riscv_edge_case_cb_type_ext
OUTPUT ${ZEPHYR_BINARY_DIR}/riscv_edge_case_cb_type_ext.llext
SOURCES ${PROJECT_SOURCE_DIR}/src/riscv_edge_case_cb_type.c ${PROJECT_SOURCE_DIR}/src/riscv_edge_case_cb_type_trigger.S
)
generate_inc_file_for_target(app ${ZEPHYR_BINARY_DIR}/riscv_edge_case_cb_type_ext.llext
${ZEPHYR_BINARY_DIR}/include/generated/riscv_edge_case_cb_type.inc
)
endif()
34 changes: 34 additions & 0 deletions tests/subsys/llext/simple/src/riscv_edge_case_cb_type.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2024 CISPA Helmholtz Center for Information Security
*
* SPDX-License-Identifier: Apache-2.0
*/

/*
* This extension tests a relocation edge case in RISC-V:
* Immediates in branch/jump-type instructions are signed-extended.
* Thus, a jump with a negative offset can have a greater jump target than
* a jump with a positive offset.
* A compressed branch (cb-type) instruction is used to trigger the edge case.
* It has a 9-bit immediate (with an implicit LSB of 0), allowing it to jump
* 256 bytes backward and 254 bytes forward.
*/

#include <stdbool.h>
#include <zephyr/llext/symbol.h>
#include <zephyr/ztest_assert.h>

extern int _riscv_edge_case_cb_trigger_forward(void);
extern int _riscv_edge_case_cb_trigger_backward(void);

void test_entry(void)
{
int test_ok;

test_ok = _riscv_edge_case_cb_trigger_forward();
zassert_equal(test_ok, 0x1);

test_ok = _riscv_edge_case_cb_trigger_backward();
zassert_equal(test_ok, 0x1);
}
EXPORT_SYMBOL(test_entry);
64 changes: 64 additions & 0 deletions tests/subsys/llext/simple/src/riscv_edge_case_cb_type_trigger.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2024 CISPA Helmholtz Center for Information Security
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/toolchain.h>

GTEXT(_riscv_edge_case_cb_trigger_backward)

/*
* Tests that jumping 256 bytes (the maximum) backwards
* using CB-type instruction is feasible
*/
SECTION_FUNC(TEXT, _riscv_edge_case_cb_trigger_backward)
/*
* tentative fail
* this needs precise alignment - need explicit compressed instructions
*/
addi a0, zero, 0
c.j _do_jump

_backward_jump_target:
/* we made it to the correct target - success, return true */
c.addi a0, 0x1
/* explicit ret */
ret


/*
* 2+4 bytes for _backward_jump_target itself
* need to insert 122 padding bytes
*/
.fill 126, 2, 0x2

_do_jump:
/* jump precisely 256 bytes, the maximum distance, backwards */
c.beqz a0, _backward_jump_target
/* should not be reached - causes return false */
ret

GTEXT(_riscv_edge_case_cb_trigger_forward)

/*
* Tests that jumping 256 bytes (the maximum) forwards
* using CB-type instruction is feasible
*/
SECTION_FUNC(TEXT, _riscv_edge_case_cb_trigger_forward)
/*
* tentative fail
* this needs precise alignment - need explicit compressed instructions
*/
addi a0, zero, 0
/* jump precisely 254 bytes, the maximum distance, forwards */
c.beqz a0, _forward_jump_target

/* need to insert 252 padding bytes to pad to 254 byte jump */
.fill 126, 2, 0x0

_forward_jump_target:
/* we made it to the correct target - success, return true */
li a0, 1
/* should not be reached - causes return false */
ret
10 changes: 9 additions & 1 deletion tests/subsys/llext/simple/src/test_llext_simple.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,15 @@ static LLEXT_CONST uint8_t multi_file_ext[] ELF_ALIGN = {
#include "multi_file.inc"
};
LLEXT_LOAD_UNLOAD(multi_file)
#endif

#if defined(CONFIG_RISCV) && defined(CONFIG_RISCV_ISA_EXT_C)
static LLEXT_CONST uint8_t riscv_edge_case_cb_type_ext[] ELF_ALIGN = {
#include "riscv_edge_case_cb_type.inc"
};
LLEXT_LOAD_UNLOAD(riscv_edge_case_cb_type)
#endif /* CONFIG_RISCV && CONFIG_RISCV_ISA_EXT_C */

#endif /* !CONFIG_LLEXT_TYPE_ELF_OBJECT */

#ifndef CONFIG_USERSPACE
static LLEXT_CONST uint8_t export_dependent_ext[] ELF_ALIGN = {
Expand Down

0 comments on commit 9381ec2

Please sign in to comment.