|
36 | 36 | * +-----+
|
37 | 37 | * |RSVD | JIT scratchpad
|
38 | 38 | * current ARM_SP => +-----+ <= (BPF_FP - STACK_SIZE + SCRATCH_SIZE)
|
| 39 | + * | ... | caller-saved registers |
| 40 | + * +-----+ |
| 41 | + * | ... | arguments passed on stack |
| 42 | + * ARM_SP during call => +-----| |
39 | 43 | * | |
|
40 | 44 | * | ... | Function call stack
|
41 | 45 | * | |
|
|
63 | 67 | *
|
64 | 68 | * When popping registers off the stack at the end of a BPF function, we
|
65 | 69 | * reference them via the current ARM_FP register.
|
| 70 | + * |
| 71 | + * Some eBPF operations are implemented via a call to a helper function. |
| 72 | + * Such calls are "invisible" in the eBPF code, so it is up to the calling |
| 73 | + * program to preserve any caller-saved ARM registers during the call. The |
| 74 | + * JIT emits code to push and pop those registers onto the stack, immediately |
| 75 | + * above the callee stack frame. |
66 | 76 | */
|
67 | 77 | #define CALLEE_MASK (1 << ARM_R4 | 1 << ARM_R5 | 1 << ARM_R6 | \
|
68 | 78 | 1 << ARM_R7 | 1 << ARM_R8 | 1 << ARM_R9 | \
|
69 | 79 | 1 << ARM_FP)
|
70 | 80 | #define CALLEE_PUSH_MASK (CALLEE_MASK | 1 << ARM_LR)
|
71 | 81 | #define CALLEE_POP_MASK (CALLEE_MASK | 1 << ARM_PC)
|
72 | 82 |
|
| 83 | +#define CALLER_MASK (1 << ARM_R0 | 1 << ARM_R1 | 1 << ARM_R2 | 1 << ARM_R3) |
| 84 | + |
73 | 85 | enum {
|
74 | 86 | /* Stack layout - these are offsets from (top of stack - 4) */
|
75 | 87 | BPF_R2_HI,
|
@@ -464,6 +476,7 @@ static inline int epilogue_offset(const struct jit_ctx *ctx)
|
464 | 476 |
|
465 | 477 | static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op)
|
466 | 478 | {
|
| 479 | + const int exclude_mask = BIT(ARM_R0) | BIT(ARM_R1); |
467 | 480 | const s8 *tmp = bpf2a32[TMP_REG_1];
|
468 | 481 |
|
469 | 482 | #if __LINUX_ARM_ARCH__ == 7
|
@@ -495,11 +508,17 @@ static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op)
|
495 | 508 | emit(ARM_MOV_R(ARM_R0, rm), ctx);
|
496 | 509 | }
|
497 | 510 |
|
| 511 | + /* Push caller-saved registers on stack */ |
| 512 | + emit(ARM_PUSH(CALLER_MASK & ~exclude_mask), ctx); |
| 513 | + |
498 | 514 | /* Call appropriate function */
|
499 | 515 | emit_mov_i(ARM_IP, op == BPF_DIV ?
|
500 | 516 | (u32)jit_udiv32 : (u32)jit_mod32, ctx);
|
501 | 517 | emit_blx_r(ARM_IP, ctx);
|
502 | 518 |
|
| 519 | + /* Restore caller-saved registers from stack */ |
| 520 | + emit(ARM_POP(CALLER_MASK & ~exclude_mask), ctx); |
| 521 | + |
503 | 522 | /* Save return value */
|
504 | 523 | if (rd != ARM_R0)
|
505 | 524 | emit(ARM_MOV_R(rd, ARM_R0), ctx);
|
|
0 commit comments