|
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