forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tests: llext: Add RISC-V CB-Type edge case test
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
1 parent
2d3390f
commit 4921ce2
Showing
4 changed files
with
173 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
120 changes: 120 additions & 0 deletions
120
tests/subsys/llext/src/riscv_edge_case_cb_type_trigger.S
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/* | ||
* 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 need to force RISC-V compressed instructions for alignment | ||
* this directive is standard in RISC-V, i.e., not toolchain-specific | ||
*/ | ||
.option push | ||
.option rvc | ||
|
||
/* we made it to the correct target - success, return true */ | ||
c.addi a0, 0x1 | ||
/* explicit compressed return */ | ||
c.jr ra | ||
|
||
|
||
/* | ||
* we need a distance of 256 bytes between _do_jump and _backward_jump_target to trigger | ||
* the edge case (max jump distance for c.beqz) | ||
* _backward_jump_target itself needs 4 bytes (two compressed instructions) | ||
* so we need to insert 252 additional padding bytes | ||
* we pad with return instructions here, causing the test to return 0 (failure) | ||
*/ | ||
.rept 126 | ||
/* explicit compressed return - 2 bytes */ | ||
c.jr ra | ||
.endr | ||
|
||
_do_jump: | ||
/* jump precisely 256 bytes, the maximum distance, backwards */ | ||
c.beqz a0, _backward_jump_target | ||
|
||
/* | ||
* in case we erroneously jump FORWARD instead of backwards, | ||
* the jump ends in the following return sled and we return 0 | ||
* this indicates test failure | ||
* note that maximum distance for jump forwards is 254 bytes, | ||
* which is also the size of this sled | ||
*/ | ||
.rept 127 | ||
/* explicit compressed return - 2 bytes */ | ||
c.jr ra | ||
.endr | ||
|
||
/* assembler can decide whether to emit compressed instructions */ | ||
.option pop | ||
|
||
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) | ||
j _test_start | ||
|
||
/* we need to force RISC-V compressed instructions for alignment */ | ||
.option push | ||
.option rvc | ||
|
||
/* | ||
* in case the relocation is incorrect and the c.beqz jumps BACKWARDS, | ||
* e.g., after arithmetic overflow, we jump into the following return sled | ||
* the return sled is 256 bytes long, covering the maximum backward jump | ||
*/ | ||
.rept 128 | ||
/* explicit compressed return - 2 bytes */ | ||
c.jr ra | ||
.endr | ||
|
||
_test_start: | ||
/* tentative fail */ | ||
addi a0, zero, 0 | ||
|
||
/* | ||
* jump precisely 254 bytes, the maximum distance, forwards | ||
* in case the relocation is applied incorrectly, we jump into the padding bytes | ||
* this causes test failure | ||
* we cannot jump too far forwards, 254 bytes is the maximum distance | ||
*/ | ||
c.beqz a0, _forward_jump_target | ||
|
||
/* | ||
* need to insert 252 padding bytes to pad to 254 byte jump | ||
* we pad with return instructions here, causing the test to return 0 (failure) | ||
*/ | ||
.rept 126 | ||
/* explicit compressed return - 2 bytes */ | ||
c.jr ra | ||
.endr | ||
|
||
/* assembler can decide whether to emit compressed instructions */ | ||
.option pop | ||
|
||
_forward_jump_target: | ||
/* we made it to the correct target - success, return true */ | ||
li a0, 1 | ||
/* should not be reached - causes return false */ | ||
ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters